package com.example.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.mapper.CachedHttpReqToResendMapper;
import com.example.model.CachedHttpReqToResend;
import com.example.reqvo.LoginReqVO;
import com.example.service.CachedHttpReqProcessor;
import com.example.service.ICachedHttpReqToResendService;
import com.example.util.EFeignClient;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class ICachedHttpReqToResendServiceImpl extends ServiceImpl<CachedHttpReqToResendMapper, CachedHttpReqToResend> implements ICachedHttpReqToResendService {
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void saveLoginReqWhenFailOver(LoginReqVO reqVO) {

        CachedHttpReqToResend req = new CachedHttpReqToResend();
        req.setHttpReqId(IdWorker.getId());
        req.setReqType(CachedHttpReqToResend.REQ_TYPE_LOGIN_TO_SERVICE_A);

        req.setThirdSysFeignName(EFeignClient.SERVICE_A.getName());

        try {
            String s = objectMapper.writeValueAsString(reqVO);
            req.setHttpReqBody(s);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }

        init(req);
        /**
         * 真实场景下，比如一个用户先后发起好几次feign调用，
         * 为了将同一个用户的feign请求排序后处理，这里可以将用户id设置进去
         */
        req.setRelatedEntityId(null);

        this.save(req);
    }


    private void init(CachedHttpReqToResend req) {
        req.setCurrentState(CachedHttpReqToResend.CURRENT_STATE_INIT);
        req.setFailCount(0);
        req.setSuccessTime(null);
        req.setCreateTime(new Date());
    }


    @Autowired
    private List<CachedHttpReqProcessor> cachedHttpReqProcessors;


    @Override
    public void processCachedFeignReqForLoginLogout() {
        String[] feignClients = {EFeignClient.SERVICE_A.getName()};

        for (String feignClient : feignClients) {
            /**
             * 根据feign client，找到对应的处理器
             */
            CachedHttpReqProcessor cachedHttpReqProcessor = cachedHttpReqProcessors.stream().filter(item -> item.support(feignClient)).findFirst().orElse(null);
            if (cachedHttpReqProcessor == null) {
                throw new RuntimeException();
            }

            /**
             * 从数据库获取要发送到该服务的请求
             */
            List<CachedHttpReqToResend> recordsFromDb = getRecordsFromDb(feignClient);
            if (CollectionUtils.isEmpty(recordsFromDb)) {
                continue;
            }

            /**
             * 利用对应的处理器，处理该部分请求
             */
            cachedHttpReqProcessor.process(recordsFromDb);
        }
    }

    private List<CachedHttpReqToResend> getRecordsFromDb(String feignClient) {
        LambdaQueryWrapper<CachedHttpReqToResend> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(CachedHttpReqToResend::getCurrentState, CachedHttpReqToResend.CURRENT_STATE_INIT, CachedHttpReqToResend.CURRENT_STATE_FAIL,
                CachedHttpReqToResend.CURRENT_STATE_FAIL_TOO_MANY_TIMES);
        wrapper.eq(CachedHttpReqToResend::getThirdSysFeignName, feignClient);
        wrapper.orderByAsc(CachedHttpReqToResend::getCreateTime);
        wrapper.last("limit 20");

        List<CachedHttpReqToResend> cachedHttpReqToResends = this.baseMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(cachedHttpReqToResends)) {
            return new ArrayList<>();
        }

        return cachedHttpReqToResends;
    }
}